/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.nls.speechhandler;


import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.SpeechReqProtocol.State;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import com.component.AliAuthService;
import com.utils.PlayUtil;
/**
 *
 * @author knight
 */
public class RealSpeechRecognitionHandler {
	
	private static Logger LOG = LoggerFactory.getLogger(RealSpeechRecognitionHandler.class);
	
    private SpeechTranscriberListener listener;
    
    private TargetDataLine targetDataLine;

    NlsClient client;
    
    public RealSpeechRecognitionHandler(SpeechTranscriberListener listener) {
        client = AliAuthService.createClient();
        this.listener = listener;
    }

    public void process() {
        SpeechTranscriber transcriber = null;
        try {
            // Step1 创建实例,建立连接
            transcriber = new SpeechTranscriber(client, listener);
            transcriber.setAppKey(AliAuthService.APP_KEY);
            // 输入音频编码方式
            transcriber.setFormat(InputFormatEnum.PCM);
            // 输入音频采样率
            transcriber.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
            // 是否返回中间识别结果
            transcriber.setEnableIntermediateResult(false);
            // 是否生成并返回标点符号
            transcriber.setEnablePunctuation(true);
            // 是否将返回结果规整化,比如将一百返回为100
            transcriber.setEnableITN(false);
            
            // Step2 此方法将以上参数设置序列化为json发送给服务端,并等待服务端确认
            transcriber.start();
            //由单独线程去pingpong
            //pingpong(transcriber);
            

            // Step3 读取麦克风数据
            AudioFormat audioFormat = new AudioFormat(16000.0F, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
            targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
            targetDataLine.open(audioFormat);
            targetDataLine.start();
            
            LOG.info("please speak !");
            final int bufSize = 6400;
            byte[] buffer = new byte[bufSize];
            while ((targetDataLine.read(buffer, 0, bufSize)) > 0) {
            	if(PlayUtil.isPlaying) {
            		if(LOG.isDebugEnabled()) {
            			LOG.debug("正在播放，不能发送信息；由pingpong方法发送心跳");
            			transcriber.getConnection().sendPing();
            		}
            	}else {
            		transcriber.send(buffer);
            	}
            }
            transcriber.stop();
        } catch (Exception e) {
        	LOG.error(e.getMessage());
        } finally {
            if (null != transcriber) {
                transcriber.close();
            }
        }
    }
    
    
    
    public void shutdown() {
    	if(targetDataLine != null) {
    		targetDataLine.close();
    		client.shutdown();
    	}
    }
    
    public void stop() {
    	 targetDataLine.flush();
    	 targetDataLine.close();
    }
    
    public void start() {
    	//targetDataLine.start();
    	//targetDataLine.close();
    	analysis();
   }
    
    private void pingpong(final SpeechTranscriber transcriber) {
    	new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(transcriber != null && State.STATE_CONNECTED.name().equals(transcriber.getState().name())) {
					try {
						Thread.sleep(2000);
						transcriber.getConnection().sendPing();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();
    }
    
    public void analysis() {
    	new Thread(()->{
    		process();
    	}).start();
    }
}
